package com.goldentrail.neo4j;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Hashtable;

import com.goldentrail.dataobject.DataArtifact;
import com.goldentrail.dataobject.Invocation;
import com.goldentrail.dataobject.Node;
import com.goldentrail.dataobject.Run;
import com.goldentrail.dml.Neo4jBuilder;
import com.goldentrail.dml.Neo4jQuery;

public class RestTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		// The following tests are all based on the DToL_FPC1_001 run from the file dtol_fpc1_out.trace
		// Note that in some of these tests I note that a test should exclude 
		//    some node from the results. The test should in those cases also 
		//    remove that node from other areas in the results, I am just 
		//    noting one of those changes to check for correct operation
		// I used separate variable names for each test so multiple tests 
		//    should be safe to run in the same execution
		// Note that 1C-1F hang on my machine due to some unknown problem 
		//    where the program hangs if it tries to make a REST call where 
		//    too much data is returned, with that limit being unreasonably 
		//    small. They consistently work on Saumen's machine. I wrote all 
		//    the other tests such that they execute on my machine

		// Test 1A:use this line to get the list of runs out of the database
		//System.out.println("Test 1A:" + Neo4jQuery.getRunIds());
		// Test 1B:use this line to get one of the runs back out of the database (this call can be slow)
		//System.out.println("Test 1B:" + Neo4jQuery.getRun("DToL_FPC1_001"));
		// Test 1C:use this line to get the complete list of invocations out of the database
		//System.out.println("Test 1C:" + Neo4jQuery.getInvocIds());
		// Test 1D:use this line to get the list of invocations in a given run
		//System.out.println("Test 1D:" + Neo4jQuery.getInvocIds("DToL_FPC1_001"));
		// Test 1E:use this line to get the complete list of data artifacts out of the database
		//System.out.println("Test 1E:" + Neo4jQuery.getDataArtifactIds());
		// Test 1F:use this line to get the list of data artifacts in a given run
		//System.out.println("Test 1F:" + Neo4jQuery.getDataArtifactIds("DToL_FPC1_001"));
		
		
		
		// Test 2:use these lines to find data dependencies of the specified node (searches left)
		// should return one invocation (AlignWarp:2) with several inputs and one output
		//ArrayList<Node> startNodes2 = new ArrayList<Node>();
		//startNodes2.add(new Node("data","313"));
		//System.out.println("Test 2:" + Neo4jQuery.getDependencies(startNodes2, null, null));
		
		
		// Test 3A:use these lines to find data dependents of the specified node (searches right)
		// note that data artifact 319 should be among ResliceWarp:2's outputs (compare with next test)
		// should return two invocations (ResliceWarp:2,SoftMean:1)
		//ArrayList<Node> endNodes3a = new ArrayList<Node>();
		//endNodes3a.add(new Node("data","313"));
		//System.out.println("Test 3A:" + Neo4jQuery.getDependents(endNodes3a, null, null));
		
		
		// Test 3B:use these lines to find data dependents of the specified node (searches right)
		// this search also includes a through node that should exclude data artifact 319 from ResliceWarp:2's outputs
		// should return two invocations (ResliceWarp:2,SoftMean:1)
		//ArrayList<Node> endNodes3b = new ArrayList<Node>();
		//ArrayList<Node> throughNodes3b = new ArrayList<Node>();
		//endNodes3b.add(new Node("data","313"));
		//throughNodes3b.add(new Node("data","320"));
		//System.out.println("Test 3B:" + Neo4jQuery.getDependents(endNodes3b, throughNodes3b, null));
		
		
		// Test 3C:use these lines to find data dependents of the specified node (searches right)
		// this search also includes a through node that should exclude data artifact 319 from ResliceWarp:2's outputs
		// should return same results as previous test, only difference is the addition of the runId
		//ArrayList<Node> endNodes3c = new ArrayList<Node>();
		//ArrayList<Node> throughNodes3c = new ArrayList<Node>();
		//endNodes3c.add(new Node("data","313"));
		//throughNodes3c.add(new Node("data","320"));
		//System.out.println("Test 3C:" + Neo4jQuery.getDependents(endNodes3c, throughNodes3c, "DToL_FPC1_001"));
		
		
		
		// Test 4A:use these lines to find a path between two nodes (searches left)
		// should return a list with 3 invocations (SoftMean:1,ResliceWarp:2,AlignWarp:2)
		// note that data artifact 319 should be among ResliceWarp:2's outputs (compare with next test)
		//Hashtable<Node, ArrayList<Node>> nodePairs4a = new Hashtable<Node, ArrayList<Node>>();
		//ArrayList<Node> endNode4a = new ArrayList<Node>();
		//endNode4a.add(new Node("data","237"));
		//nodePairs4a.put(new Node("data","357"), endNode4a);
		//System.out.println("Test 4A:" + Neo4jQuery.getPaths(nodePairs4a, null, null));
		
		// Test 4B:use these lines to find a path between two nodes (searches left)
		// this search also includes a through node that should exclude data artifact 319 from ResliceWarp:2's outputs
		// should return a list with 3 invocations (SoftMean:1,ResliceWarp:2,AlignWarp:2)
		//Hashtable<Node, ArrayList<Node>> nodePairs4b = new Hashtable<Node, ArrayList<Node>>();
		//ArrayList<Node> endNode4b = new ArrayList<Node>();
		//endNode4b.add(new Node("data","237"));
		//nodePairs4b.put(new Node("data","357"), endNode4b);
		//ArrayList<Node> throughNodes4b = new ArrayList<Node>();
		//throughNodes4b.add(new Node("data","320"));
		//System.out.println("Test 4B:" + Neo4jQuery.getPaths(nodePairs4b, throughNodes4b, null));
		
		// Test 4C:use these lines to find a path between two nodes (searches left)
		// this search also includes a through node that should exclude data artifact 319 from ResliceWarp:2's outputs
		// should return same as previous test. only difference is addition of run id
		//Hashtable<Node, ArrayList<Node>> nodePairs4c = new Hashtable<Node, ArrayList<Node>>();
		//ArrayList<Node> endNode4c = new ArrayList<Node>();
		//endNode4c.add(new Node("data","237"));
		//nodePairs4c.put(new Node("data","357"), endNode4c);
		//ArrayList<Node> throughNodes4c = new ArrayList<Node>();
		//throughNodes4b.add(new Node("data","320"));
		//System.out.println("Test 4C:" + Neo4jQuery.getPaths(nodePairs4c, throughNodes4c, "DToL_FPC1_001"));
		

		
		//
		// Other random testing code below
		//
		
		
		// Uncomment these two lines to fill the database with the project
		// described in 7-1-2011 Workflow Notes
		//create_r0();
		//create_r1();
		
		/*ArrayList<Node> startNodes = new ArrayList<Node>();
		ArrayList<Node> throughNodes = new ArrayList<Node>();
		startNodes.add(new Node("data","313"));
		throughNodes.add(new Node("data","357"));
		System.out.println("Test 3C:" + Neo4jQuery.getDependents(startNodes, throughNodes, null));*/
		
		
		/*Neo4jNode startNode = Neo4jNode.getNode("data", "id", "d4");
		ArrayList<RelationshipSpec> rels = new ArrayList<RelationshipSpec>();
		rels.add(new RelationshipSpec("GEN_BY","out"));
		rels.add(new RelationshipSpec("USED","out"));
		TraverserSpec t = new TraverserSpec();
		t.setOrder(TraverserSpec.DEPTH_FIRST);
		t.setUniqueness(TraverserSpec.NODE_PATH_UNIQUENESS);
		t.setMaxDepth(100);
		t.setReturnFilter(TraverserSpec.ALL_RETURN_FILTER, TraverserSpec.BUILTIN_LANG, null);
		t.setPruneEvaluator(TraverserSpec.JAVASCRIPT_LANG, "position.endNode().hasProperty('run')&&position.endNode().getProperty('run')!='r1'");
		t.setRelationships(rels);
		System.out.println(startNode.traverseNode(t));*/
		
		
		/*ArrayList<Node> startNodes = new ArrayList<Node>();
		ArrayList<Node> throughNodes = new ArrayList<Node>();
		startNodes.add(new Node("data","313"));
		System.out.println(Neo4jQuery.getDependencies(startNodes, throughNodes, null));*/
		
		
		
		/*ArrayList<Node> startNodes = new ArrayList<Node>();
		startNodes.add(new Node("data", "237"));
		//startNodes.add(new Node("data", "357"));
		ArrayList<Node> throughNodes = new ArrayList<Node>();
		throughNodes.add(new Node("data","320"));
		//throughNodes.add(new Node("data","237"));
		System.out.println(Neo4jQuery.getDependents(startNodes, throughNodes, "DToL_FPC1_001"));*/
		
		
		/*ArrayList<Node> startNodes = new ArrayList<Node>();
		//startNodes.add(new Node("invoc", "ResliceWarp:2"));
		startNodes.add(new Node("data", "358"));
		//ArrayList<Node> throughNodes = new ArrayList<Node>();
		//throughNodes.add(new Node("data","320"));
		System.out.println(Neo4jQuery.getDependencies(new Node("invoc","SoftMean:1"), null));*/
		
		
		//Neo4jNode runNode = Neo4jNode.getNode("run", "id", "DToL_FPC1_001");
		//System.out.println(Neo4jQuery.getRun("DToL_FPC1_001").getInvocations());
		
		
		/*Hashtable<Node, ArrayList<Node>> nodePairs = new Hashtable<Node, ArrayList<Node>>();
		ArrayList<Node> throughNodes = new ArrayList<Node>();
		throughNodes.add(new Node("data","320"));
		ArrayList<Node> endNodes = new ArrayList<Node>();
		endNodes.add(new Node("data", "313"));
		endNodes.add(new Node("data", "299"));
		nodePairs.put(new Node("data","357"), endNodes);
		System.out.println("Results: " + Neo4jQuery.getPaths(nodePairs, throughNodes, "DToL_FPC1_001"));*/
		
		
		
		/*ArrayList<Node> nodes = new ArrayList<Node>();
		//nodes.add(new Node("data", "320"));
		//nodes.add(new Node("data", "d2"));
		Neo4jNode node = Neo4jNode.getNode("data", "id", "357");
		ArrayList<RelationshipSpec> rels = new ArrayList<RelationshipSpec>();
		rels.add(new RelationshipSpec(Neo4jBuilder.GEN_BY_REL, "out"));
		rels.add(new RelationshipSpec(Neo4jBuilder.USED_REL, "out"));
		TraverserSpec t = new TraverserSpec();
		t.setRelationships(rels);
		t.setMaxDepth(1000);
		t.setOrder(TraverserSpec.DEPTH_FIRST);
		t.setUniqueness(TraverserSpec.NODE_GLOBAL_UNIQUENESS);
		//t.setReturnFilter(null, TraverserSpec.JAVASCRIPT_LANG, "position.endNode().getProperty('type')=='invoc'");
		t.setReturnFilter(TraverserSpec.ALL_RETURN_FILTER, TraverserSpec.BUILTIN_LANG, null);
		t.setReturnFilter(null, TraverserSpec.JAVASCRIPT_LANG, 
				"position.endNode().getProperty('id')=='320'||" +
				"position.endNode().getProperty('id')=='319'||" +
				"position.endNode().getProperty('id')=='306'||" +
				"position.endNode().getProperty('id')=='305'||" +
				"position.endNode().getProperty('id')=='349'||" +
				"position.endNode().getProperty('id')=='348'||" +
				"position.endNode().getProperty('id')=='333'||" +
				"position.endNode().getProperty('id')=='334'||" +
				"position.endNode().getProperty('id')=='313'");*/
		/*t.setReturnFilter(null, TraverserSpec.JAVASCRIPT_LANG, "" +
				"(function eval(pos) {" +
				"var throughNodes = " + nodes.toString() + ";" +
				"var i = " + nodes.size() + ";" +
				//check each through node
				"while(i--) {" +
				"var hasThroughNode=false;" +
				"var throughNode = throughNodes[i];" +
				"var nodeIt = pos.nodes().iterator();" +
				"var node = null;" +
				"while(nodeIt.hasNext()) {" +
				"node = nodeIt.next();" +
				"if(node.getProperty('type')==throughNode.type) {" +
				"if(node.getProperty('id')==throughNode.id) {" +
				"hasThroughNode=true;" +
				"break;" +
				"}" +
				"}" +
				"}" +
				"if (!hasThroughNode)" +
				"return false;" +
				"}" +
				"return true;" +
				"})(position)");*/
		//node.traverseNode(t);
		//URI URINext = null;
		//node.traverseNode(t);
		//System.out.println(node.traverseNodePaged(t, URINext));
		//System.out.println(node.traverseNode(t));
		
		//ArrayList<Neo4jNode>nodes = new ArrayList<Neo4jNode>();
		//nodes.add(new Neo4jNode("gobbles"));
		//System.out.println(nodes.contains(new Neo4jNode("gobbles")));
		
		
		//ArrayList<String> results = Neo4jQuery.getInvocIds();
		//ArrayList<String> results = Neo4jQuery.getRunIds();
		//System.out.println("Invocations in database: ");
		//System.out.println(results);
		
		
		//ArrayList<Invocation> invocs = Neo4jQuery.getDependencies("d4", "r1"); 
		//System.out.println(invocs);
		
		
		/*Node startNode = new Node();
		Node endNode = new Node();
		startNode.setNodeTp("data");
		startNode.setNodeId("357");
		endNode.setNodeTp("data");
		endNode.setNodeId("313");
		ArrayList<Invocation> invocs = Neo4jQuery.getPaths(startNode, endNode);
		System.out.println(invocs);*/
		
		
		/*Neo4jNode tim = Neo4jNode.createNode();
		Neo4jNode sam = Neo4jNode.createNode();
		tim.addProperty("Name", "Tim");
		sam.addProperty("Name", "Sam");
		tim.indexNode("node", "id", "Person");
		sam.indexNode("node", "id", "Person");*/
		//ArrayList<Neo4jNode> nodes = Neo4jNode.getNodes("node", "id", "Person"*/
		
		
		/*PathSpec path = new PathSpec();
		path.setAlgorithm(PathSpec.SHORTEST_PATH);
		path.setMaxDepth(10);
		path.setToNode(Neo4jNode.getNode("data", "id", "d3"));
		ArrayList<RelationshipSpec> rels = new ArrayList<RelationshipSpec>();
		rels.add(new RelationshipSpec("USED", "out"));
		rels.add(new RelationshipSpec("GEN_BY", "out"));
		path.setRelationships(rels);
		Neo4jNode.getNode("data", "id", "d4").findPath(path);*/

		
		/*Neo4jNode dbRun = Neo4jNode.getNode("run", "id", "r1");
		Traverser t = new Traverser();
		t.setMaxDepth(2);
		// t.setPruneEvaluator(Traverser.JAVASCRIPT_LANG,
		// "position.endNode().hasRelationship('out','RUN_INVOC')&&"+
		// "position.endNode().getSingleRelationship('RUN_INVOC','out')"+
		// ".getEndNode().getProperty('id')!='" + r.getRunId() + "'");
		t.setReturnFilterLanguage(Traverser.JAVASCRIPT_LANG);
		String returnFilter = "";
		returnFilter = "(function eval(pos) {"
				+ "var node = pos.endNode();"
				+
				// "if (node.getProperty('type')!='data')" +
				// "return false;" +
				// "if(position.endNode().hasRelationship('out','GEN_BY'))" +
				// "return true;" +
				// "if (pos.length()<1)" +
				// "return false;" +
				// "if (pos.length()>0&&pos.lastRelationship().getType()=='USED')"
				// +
				// "return true;" +
				// "return node.getProperty('id')=='d2';" +
				"var rels = node.getRelationships();"
				+ "var relIt = rels.iterator();" + "return relIt.hasNext();" +
				// "var rel=null;" +
				// "while(relIt.hasNext()){" +
				// "rel = relIt.next();" +
				// "if (rel.getType()=='GEN_BY')" +
				"return false;" +
				// "}" +
				// "return true;" +
				"})(position);";
		// returnFilter = "true";
		t.setReturnFilterBody(returnFilter);
		// t.setReturnFilterBody("position.endNode().getProperty('type')=='data'&&"
		// +
		// "(!position.endNode().hasRelationship('out','GEN_BY')||" +
		// "position.endNode()" +
		// ".getSingleRelationship('GEN_BY','out').getEndNode()" +
		// ".getSingleRelationship('RUN_INVOC','out').getEndNode()" +
		// ".getProperty('id')!='" + "r1" + "')");
		t.setUniqueness(Traverser.NODE_PATH_UNIQUENESS);
		t.setOrder(Traverser.DEPTH_FIRST);
		ArrayList<TraverserRelationship> rels = new ArrayList<TraverserRelationship>();
		rels.add(new TraverserRelationship("RUN_INVOC", "in"));
		rels.add(new TraverserRelationship("USED", "out"));
		// rels.add(new TraverserRelationship(GEN_BY_REL, "out"));
		t.setRelationships(rels);
		System.out.println("NOW TRAVERSING FOR INPUTS");
		ArrayList<Neo4jNode> initInputs = dbRun.traverseNode(t);*/

		
		// Neo4jNode n1 = Neo4jNode.createNode();
		// Neo4jNode n1 = Neo4jNode.getNode("my_nodes", "name", "Fred");
		// n1.addProperty("name", "Fred");
		// n1.indexNode("my_nodes", "name", "Fred");
		// Neo4jNode n = Neo4jNode.getNode(1);

		// Neo4jNode n2 = Neo4jNode.createNode();
		// Neo4jNode n2 = Neo4jNode.getNode("my_nodes", "name", "Jim");
		/*
		 * n2.addProperty("name", "Jim"); n2.indexNode("my_nodes", "name",
		 * "Jim"); try { n1.addRelationship(n2, "FRIENDS"); } catch
		 * (URISyntaxException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); }
		 */

		
		// ArrayList<Relationship> relationships = n1.getRelationships("all");
		// for (Relationship r : relationships) {
		// //System.out.println(r.get)
		//
		// }
		// n1.getRelationships("all","JIMMY");

		// System.out.println("Retrieved Name: \"" + n.getProperty("Name") +
		// "\"");
		// System.out.println("Node string: " + n1.toString());

		// System.out.println(r.getRunId());
		 return;

	}

	private static void create_r1() {
		Run r1 = new Run();
		ArrayList<Invocation> r1invoc = new ArrayList<Invocation>();
		DataArtifact d1 = new DataArtifact();
		DataArtifact d2 = new DataArtifact();
		DataArtifact d3 = new DataArtifact();
		DataArtifact d4 = new DataArtifact();
		Invocation i1 = new Invocation();
		Invocation i2 = new Invocation();

		d1.setDataArtifactId("d1");
		d2.setDataArtifactId("d2");
		d3.setDataArtifactId("d3");
		d4.setDataArtifactId("d4");
		
		d1.setValueType("String");
		d2.setValueType("String");
		d3.setValueType("String");
		d4.setValueType("String");
		
		d1.setValue("d1");
		d2.setValue("d2");
		d3.setValue("d3");
		d4.setValue("d4");

		i1.setInvocationId("i1");
		i2.setInvocationId("i2");

		r1.setRunId("r1");

		Hashtable<String, DataArtifact> i1in = new Hashtable<String, DataArtifact>();
		Hashtable<String, DataArtifact> i1out = new Hashtable<String, DataArtifact>();

		Hashtable<String, DataArtifact> i2in = new Hashtable<String, DataArtifact>();
		Hashtable<String, DataArtifact> i2out = new Hashtable<String, DataArtifact>();

		i1in.put("d1", d1);
		i1out.put("d2", d2);

		i2in.put("d2", d2);
		i2in.put("d3", d3);
		i2out.put("d4", d4);

		i1.setInputData(i1in);
		i1.setOutputData(i1out);

		i2.setInputData(i2in);
		i2.setOutputData(i2out);

		r1invoc.add(i1);
		r1invoc.add(i2);
		r1.setInvocations(r1invoc);

		Neo4jBuilder.AddToDB(r1);
	}

	private static void create_r0() {
		Run r0 = new Run();
		r0.setRunId("r0");

		DataArtifact d0 = new DataArtifact();
		DataArtifact d1 = new DataArtifact();
		Invocation i0 = new Invocation();

		i0.setInvocationId("i0");
		d0.setDataArtifactId("d0");
		d1.setDataArtifactId("d1");
		
		d0.setValueType("String");
		d1.setValueType("String");
		
		d0.setValue("d0");
		d1.setValue("d1");

		Hashtable<String, DataArtifact> i0in = new Hashtable<String, DataArtifact>();
		Hashtable<String, DataArtifact> i0out = new Hashtable<String, DataArtifact>();

		ArrayList<Invocation> r0invoc = new ArrayList<Invocation>();

		i0in.put("d0", d0);
		i0out.put("d1", d1);

		i0.setInputData(i0in);
		i0.setOutputData(i0out);

		r0invoc.add(i0);
		r0.setInvocations(r0invoc);

		Neo4jBuilder.AddToDB(r0);
	}

}
